﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using MadLibrary;
using MadLibrary.Text;

namespace MadLibrary.Web
{
    /// <summary>
    /// Holds information about HTML element.
    /// </summary>
    public class HtmlElement : IRefactorBuildable
    {
        /// <summary>
        /// Gets or sets name of current element.
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// Gets or sets HTML sub-element collection of current element.
        /// </summary>
        public HtmlElements Elements { get; set; }

        /// <summary>
        /// Gets or sets attributes of current element.
        /// </summary>
        public HtmlAttributes Attributes { get; set; }

        /// <summary>
        /// Gets or sets type of current element.
        /// </summary>
        public ElementType Type { get; set; }

        /// <summary>
        /// Gets or sets inner text of current element.
        /// </summary>
        public string InnerText { get; set; }

        /// <summary>
        /// Creates new empty HTML element.
        /// </summary>
        public HtmlElement()
        {
            this.Name = "";
            this.Elements = new HtmlElements();
            this.Attributes = new HtmlAttributes();
        }

        /// <summary>
        /// Creates new HTML element with specified name.
        /// </summary>
        /// <param name="Name">Specifies name of new element.</param>
        public HtmlElement(string Name)
        {
            this.Name = Name;
            this.Elements = new HtmlElements();
            this.Attributes = new HtmlAttributes();
            this.Type = ElementType.Simple;
        }

        /// <summary>
        /// Creates new HTML element with specified name and specified type.
        /// </summary>
        /// <param name="Name">Specifies name of new HTML element.</param>
        /// <param name="Type">Specifies type of new HTML element.</param>
        public HtmlElement(string Name, ElementType Type)
        {
            this.Name = Name;
            this.Elements = new HtmlElements();
            this.Attributes = new HtmlAttributes();
            this.Type = Type;
        }

        /// <summary>
        /// Creates new HTML element with specified name and specified collection of HTML sub-elements.
        /// </summary>
        /// <param name="Name">Specifies name of new HTML element.</param>
        /// <param name="elements">Specifies HTML sub-element collection of current element.</param>
        public HtmlElement(string Name, HtmlElements elements)
        {
            this.Name = Name;
            this.Elements = elements;
            this.Attributes = new HtmlAttributes();
            this.Type = ElementType.Compound;
        }

        /// <summary>
        /// Creates new HTML element with specified name, specified collection of sub-elements and specified collection of HTML attributes.
        /// </summary>
        /// <param name="Name">Specifies name of new HTML element.</param>
        /// <param name="elements">Specifies HTML sub-element collection of new element.</param>
        /// <param name="attributes">Specifies HTML attribute collection of new element.</param>
        public HtmlElement(string Name, HtmlElements elements, HtmlAttributes attributes)
        {
            this.Name = Name;
            this.Elements = elements;
            this.Attributes = attributes;
            this.Type = ElementType.Compound;
        }

        /// <summary>
        /// Creates new HTML element from specified ParsedNode.
        /// </summary>
        /// <param name="nod">Specifies ParsedNode from which should be built new HTML element.</param>
        public HtmlElement(ParsedNode nod)
        {
            this.Name = nod.Name;
            this.Elements = new HtmlElements();
            this.Attributes = new HtmlAttributes();
            if(nod.Type == NodeType.OneLine)
                this.Type = ElementType.Simple;
            else this.Type = ElementType.Compound;
        }

        /// <summary>
        /// Generates string of current HTML element and its sub-elements.
        /// </summary>
        /// <param name="dept">Specifies tabulator dept for string generation.</param>
        /// <returns>String generated from current HTML element and its sub-elements.</returns>
        string IRefactorBuildable.Build(int dept)
        {
            string r = "";
            string atts = "";
            string refact = "".Tabulate(dept);
            foreach(HtmlAttribute a in this.Attributes)
            {
                atts += (a as IBuildable).Build();
            }
            string selements = "";
            foreach(HtmlElement e in this.Elements)
            {
                selements += (e as IRefactorBuildable).Build(dept + 1);
            }
            if(this.Type == ElementType.Simple)
                r = String.Format("<{0}{1} />", this.Name, atts);
            else if(this.Type == ElementType.Compound)
                r = string.Format("<{0}{1}>\r\n{3}{4}\r\n{2}{3}</{0}>", this.Name, atts, selements, refact, this.InnerText);
            else
                r = string.Format("<!DOCTYPE{0}>", atts);

            return refact + r + Environment.NewLine;
        }
    }
}